home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 3 / Gold Medal Software - Volume 3 (Gold Medal) (1994).iso / os2 / ssaver2x.arj / POLYLINE.C < prev    next >
Text File  |  1994-01-06  |  20KB  |  587 lines

  1. /*
  2.     polylines.c
  3.     Polylines saver module C source file
  4.     (C) 1993 Toniolo Emanuele
  5. */
  6.  
  7. #define INCL_DOS
  8. #define INCL_DOSERRORS
  9. #define INCL_WIN
  10. #define INCL_GPI
  11. #define INCL_PM
  12. #include <os2.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <limits.h>
  17. #include <process.h>
  18.  
  19. #include "polyline.h"
  20.  
  21.  
  22. // ===== preprocessor definitions
  23.  
  24. #define MODULEVERSION            0x00010001
  25. #define STACKSIZE                32000
  26. #define SAVER_NAME_MAXLEN              32
  27. #define FUNCTION_CONFIGURE             1
  28. #define FUNCTION_STARTSAVER            2
  29. #define FUNCTION_STOPSAVER         3
  30. #define FUNCTION_QUERYNAME         4
  31. #define FUNCTION_QUERYENABLED        5
  32. #define FUNCTION_SETENABLED            6
  33.  
  34. #define CONFIGURATION_MINIMUM_COUNT          1
  35. #define CONFIGURATION_DEFAULT_COUNT          20
  36. #define CONFIGURATION_MAXIMUM_COUNT          300
  37. #define CONFIGURATION_POLY_MINIMUM_COUNT      1
  38. #define CONFIGURATION_POLY_DEFAULT_COUNT      1
  39. #define CONFIGURATION_POLY_MAXIMUM_COUNT      20
  40. #define CONFIGURATION_POLY_DEFAULT_TYPE        0
  41. #define CONFIGURATION_POLY_DEFAULT_CLOSED      TRUE
  42.  
  43.  
  44. // ===== prototypes
  45.  
  46. void    EXPENTRY SAVER_PROC(int function, HAB _hab, HWND hwndOwner, char *appname, void *buffer);
  47. static    MRESULT EXPENTRY SaverWindowProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  48. static    MRESULT    EXPENTRY ConfigureDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  49. #if defined(__IBMC__)
  50. static    void    _Optlink draw_thread(void *args);
  51. static    void    _Optlink priority_thread(void *args);
  52. #elif defined(__BORLANDC__)
  53. static    void    _USERENTRY draw_thread(void *args);
  54. static    void    _USERENTRY priority_thread(void *args);
  55. #else
  56. static    void    draw_thread(void *args);
  57. static    void    priority_thread(void *args);
  58. #endif
  59. static    void    load_configuration_data(void);
  60.  
  61.  
  62.  
  63. // ===== global data
  64.  
  65. static    LONG    screenSizeX = 0;        // screen size x
  66. static    LONG    screenSizeY = 0;        // screen size y
  67. static    HWND    hwndSaver = NULLHANDLE;        // saver window handle
  68. static    HMODULE    hmodDLL = NULLHANDLE;        // saver module dll handle
  69. static    char    *application_name;        // name of ScreenSaver app
  70. static    TID    tidDraw;            // drawing-thread ID
  71. static    HPS    hps;                // presentation space handle
  72. static    HAB    hab;                // anchor block handle
  73. static    BOOL    low_priority = TRUE;        // low-priority flag
  74. static    BOOL    configuration_data_loaded = FALSE; // config data loaded flag
  75. static    volatile BOOL stop_draw_thread;        // stop flag
  76. static    char    modulename[SAVER_NAME_MAXLEN+1]; // module name buffer
  77.  
  78. static    struct    _configuration_data {
  79.     ULONG    version;
  80.     BOOL    enabled;
  81.     long    count;
  82.     long    sides;
  83.     BOOL    closed;
  84.     BOOL    use_line;
  85.         BOOL    use_curve; 
  86. } configuration_data;
  87.  
  88.  
  89. // ===== code
  90.  
  91. /*
  92.     SAVER_PROC
  93.     This is the entry point into the saver module that is called by
  94.     the ScreenSaver program.
  95.     There should be no reason to alter the code.
  96.     Depending on the requested function, the following tasks
  97.     are performed:
  98.     * call the configuration dialog of the saver module
  99.     * copy the name of the saver module into the supplied buffer
  100.     * tell if the saver module is enabled
  101.     * set the "enabled" state of the saver module
  102.     * start the saver
  103.     * stop the saver
  104.     Note that before any processing is done, module configuration data is
  105.     loaded from the INI-files.
  106. */
  107. void    EXPENTRY SAVER_PROC(int function, HAB _hab, HWND hwndOwner, char *appname, void *buffer)
  108. {
  109. #if defined(__BORLANDC__)
  110.     extern ULONG _os2hmod;
  111.     hmodDLL = _os2hmod;
  112. #endif    
  113.     hab = _hab;
  114.     application_name = appname;
  115.     // load all configuration data from INI-file
  116.     load_configuration_data();
  117.     switch(function){
  118.     case FUNCTION_CONFIGURE:
  119.         // call the configuration dialog
  120.         WinDlgBox(HWND_DESKTOP, hwndOwner, ConfigureDlgProc,
  121.           hmodDLL, IDD_CONFIGURE, application_name);
  122.         return;
  123.     case FUNCTION_STARTSAVER:
  124.         // start the saver
  125.         // get "low priority" state from supplied buffer (BOOL *)
  126.         low_priority = *((BOOL *)buffer);
  127.         // random seed
  128.         srand(WinGetCurrentTime(hab));
  129.         // query size of screen
  130.         screenSizeX = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
  131.         screenSizeY = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
  132.         // register window class for the saver window
  133.         WinRegisterClass(hab, modulename,
  134.           (PFNWP)SaverWindowProc, 0, 0);
  135.         // create the saver window
  136.         hwndSaver = WinCreateWindow(HWND_DESKTOP, modulename,
  137.           (PSZ)NULL, WS_VISIBLE, 0, 0, screenSizeX, screenSizeY,
  138.           HWND_DESKTOP, HWND_TOP, 0, NULL, NULL);
  139.         return;
  140.     case FUNCTION_STOPSAVER:
  141.         // stop the saver
  142.         if(hwndSaver != NULLHANDLE){
  143.             // move saver window to front
  144.             WinSetWindowPos(hwndSaver, HWND_TOP,
  145.               0, 0, 0, 0, SWP_ZORDER);
  146.             // destroy saver window
  147.             WinDestroyWindow(hwndSaver);
  148.             hwndSaver = NULLHANDLE;
  149.         }
  150.         return;
  151.     case FUNCTION_QUERYNAME:
  152.         // copy module name to supplied buffer (CHAR *)
  153.         strcpy(buffer, modulename);
  154.         return;
  155.     case FUNCTION_QUERYENABLED:
  156.         // copy "enabled" state to supplied buffer (BOOL *)
  157.         *((BOOL *)buffer) = configuration_data.enabled;
  158.         return;
  159.     case FUNCTION_SETENABLED:
  160.         // get new "enabled" state from supplied buffer (BOOL *)
  161.         configuration_data.enabled = *((BOOL *)buffer);
  162.         PrfWriteProfileData(HINI_USER, (PSZ)application_name, (PSZ)modulename, (PSZ)&configuration_data, sizeof(configuration_data));
  163.         return;
  164.     }
  165.  
  166.     // illegal function request
  167.     WinAlarm(HWND_DESKTOP, WA_ERROR);
  168.     return;
  169. }
  170.  
  171. #if !defined(__BORLANDC__)
  172. /*
  173.     _DLL_InitTerm
  174.     This procedure is called at DLL initialization and termination.
  175.     There should be no reason to alter the code.
  176. */
  177. ULONG    _DLL_InitTerm(HMODULE hmod, ULONG flag)
  178. {
  179.     switch(flag){
  180.     case 0:    // initializing DLL
  181.         hmodDLL = hmod;
  182.         return 1;
  183.     case 1: // terminating DLL
  184.         return 1;
  185.     default:
  186.         // return error
  187.         return 0;
  188.     }
  189. }
  190. #endif
  191.  
  192. /*
  193.     ConfigureDlgProc
  194.     This is the dialog procedure for the module configuration dialog.
  195.     The dialog contains a check box for enabling/disabling the module
  196.     and two push buttons ("OK" and "Cancel") to close/cancel the dialog.
  197.     This is enough for simple saver modules, but can easily be expanded
  198.     for more saver modules that need more settings.
  199. */
  200. MRESULT    EXPENTRY ConfigureDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  201. {
  202.     char    buf[sizeof(modulename)+20];
  203.     static    HWND    hwndEnabled,hwndClosed;
  204.     static    HWND    hwndCount,hwndPoly,hwndType;
  205.  
  206.     switch(msg){
  207.     case WM_INITDLG:
  208.         // set titlebar of the dialog window
  209.         // to "MODULENAME configuration"
  210.         strcpy(buf, modulename);
  211.         strcat(buf, " configuration");
  212.         WinSetWindowText(hwnd, buf);
  213.  
  214.         // get  window handles of the dialog controls
  215.         // and set initial state of the controls
  216.         hwndEnabled = WinWindowFromID(hwnd, IDC_ENABLED);
  217.         WinSendMsg(hwndEnabled, BM_SETCHECK,MPFROMSHORT(configuration_data.enabled), MPVOID);
  218.  
  219.         hwndClosed = WinWindowFromID(hwnd, IDC_CLOSE);
  220.         WinSendMsg(hwndClosed, BM_SETCHECK,MPFROMSHORT(configuration_data.closed), MPVOID);
  221.  
  222.         hwndCount = WinWindowFromID(hwnd, IDC_COUNT);
  223.         WinSendMsg(hwndCount, SPBM_SETLIMITS, (MPARAM)CONFIGURATION_MAXIMUM_COUNT, (MPARAM)CONFIGURATION_MINIMUM_COUNT);
  224.         WinSendMsg(hwndCount, SPBM_SETCURRENTVALUE, MPFROMSHORT(configuration_data.count), MPVOID);
  225.  
  226.         hwndPoly = WinWindowFromID(hwnd, IDC_SIDE);
  227.         WinSendMsg(hwndPoly, SPBM_SETLIMITS, (MPARAM)CONFIGURATION_POLY_MAXIMUM_COUNT, (MPARAM)CONFIGURATION_POLY_MINIMUM_COUNT);
  228.         WinSendMsg(hwndPoly, SPBM_SETCURRENTVALUE, MPFROMSHORT(configuration_data.sides), MPVOID);
  229.  
  230.         hwndType =  WinWindowFromID ( hwnd , IDC_TYPE);
  231.         WinInsertLboxItem ( hwndType, LIT_END, "Line\0" );
  232.         WinInsertLboxItem ( hwndType, LIT_END, "Curve\0" );
  233.                 if ( configuration_data.use_line )
  234.             WinSendDlgItemMsg ( hwnd,IDC_TYPE,LM_SELECTITEM,MPFROMSHORT(0),MPFROMSHORT(TRUE));
  235.                 if ( configuration_data.use_curve )
  236.             WinSendDlgItemMsg ( hwnd,IDC_TYPE,LM_SELECTITEM,MPFROMSHORT(1),MPFROMSHORT(TRUE));
  237.      
  238.         // return FALSE since we did not change the focus        
  239.                 return (MRESULT)FALSE;
  240.  
  241.  
  242.     case WM_COMMAND:
  243.         switch(SHORT1FROMMP(mp1)){
  244.         case IDC_OK:
  245.             // OK button was pressed. query the control settings
  246.             configuration_data.enabled = SHORT1FROMMR(WinSendMsg(hwndEnabled, BM_QUERYCHECK, MPVOID, MPVOID));
  247.             configuration_data.closed = SHORT1FROMMR(WinSendMsg(hwndClosed, BM_QUERYCHECK, MPVOID, MPVOID));
  248.             if (WinQueryLboxSelectedItem ( hwndType ) == 0 )
  249.                            {   
  250.                            configuration_data.use_line = TRUE;
  251.                            configuration_data.use_curve = FALSE;
  252.                            }
  253.                         if (WinQueryLboxSelectedItem ( hwndType ) == 1 )
  254.                            {   
  255.                            configuration_data.use_line = FALSE;
  256.                            configuration_data.use_curve = TRUE;
  257.                            }
  258.             WinSendMsg(hwndCount, SPBM_QUERYVALUE, MPFROMP(&configuration_data.count), MPFROM2SHORT(0, SPBQ_DONOTUPDATE));
  259.             WinSendMsg(hwndPoly, SPBM_QUERYVALUE, MPFROMP(&configuration_data.sides), MPFROM2SHORT(0, SPBQ_DONOTUPDATE));
  260.  
  261.             if ((configuration_data.use_curve) && ( configuration_data.sides < 2))
  262.                 configuration_data.sides = 2;
  263.  
  264.             // write all configuration data to INI-file
  265.             PrfWriteProfileData(HINI_USER, (PSZ)application_name, (PSZ)modulename, (PSZ)&configuration_data, sizeof(configuration_data));
  266.             // end dialog
  267.             WinDismissDlg(hwnd, TRUE);
  268.             return (MRESULT)0;
  269.         case IDC_CANCEL:
  270.             // dialog was cancelled; end it
  271.             WinDismissDlg(hwnd, FALSE);
  272.             return (MRESULT)0;
  273.         default:
  274.             return (MRESULT)0;
  275.         }
  276.     }
  277.     return WinDefDlgProc(hwnd, msg, mp1, mp2);
  278. }
  279.  
  280. /*
  281.     SaverWindowProc
  282.     This is the window procedure of the screen-size window that is
  283.     created when the saver starts.
  284.     There should be no reason to alter the code.
  285.     Note that we do not process WM_PAINT messages. They are forwarded to
  286.     the default window procedure, which just validates the window area
  287.     and does no drawing. All drawing to the window should be done in
  288.     the drawing-thread. Therefore, if you want to blank the screen before
  289.     drawing on it for instance, issue a WinFillRect call at the beginning
  290.     of your drawing-thread.
  291. */
  292. MRESULT EXPENTRY SaverWindowProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  293. {
  294.     static    TID    tidPriority;
  295.  
  296.     switch(msg){
  297.     case WM_CREATE:
  298.         // reset the "stop" flag
  299.         stop_draw_thread = FALSE;
  300.         // store window handle
  301.         hwndSaver = hwnd;
  302.         // get presentation space
  303.         hps = WinGetPS(hwnd);
  304.         // start the drawing-thread
  305. /*
  306.         $$$$$ note $$$$$
  307.         Some compilers use another parameter ordering for
  308.         _beginthread. The _beginthread call below works with EMX,
  309.         ICC and BCC. Check your compiler docs for other compilers.
  310. */
  311. // !!!!! code for Borland C++ added since version 1.0
  312. #if defined(__BORLANDC__)
  313.         // for Borland C++
  314.         tidDraw = _beginthread(draw_thread, STACKSIZE, NULL);
  315. #elif defined(__EMX__) || defined(__IBMC__)
  316.         // for EMX and ICC
  317.         tidDraw = _beginthread(draw_thread, NULL, STACKSIZE, NULL);
  318. #endif
  319.  
  320.         // !!!!! next 3 lines added since version 1.0, some code deleted
  321.         // create thread to control priority of drawing thread
  322.         if(low_priority)
  323.             DosCreateThread(&tidPriority, (PFNTHREAD)priority_thread, 0, 2L, 1000);
  324.         return (MRESULT)FALSE;
  325.  
  326.     case WM_DESTROY:
  327.         if(low_priority)
  328.             DosKillThread(tidPriority);
  329.         // tell drawing-thread to stop
  330.         stop_draw_thread = TRUE;
  331.         if(DosWaitThread(&tidDraw, DCWW_NOWAIT) == ERROR_THREAD_NOT_TERMINATED){
  332.             // if priority of drawing-thread was set to idle time
  333.             // priority, set it back to normal value
  334.             DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, tidDraw);
  335.             // wait until drawing-thread has ended
  336.             DosWaitThread(&tidDraw, DCWW_WAIT);
  337.         }
  338.         // release the presentation space
  339.         WinReleasePS(hps);
  340.         break;
  341.     case WM_PAINT:
  342.         return WinDefWindowProc(hwnd, msg, mp1, mp2);
  343.         if(0){
  344.             // just validate the update area. all drawing is done
  345.             // in the drawing-thread.
  346.             RECTL    rclUpdate;
  347.             HPS    hps = WinBeginPaint(hwnd, NULLHANDLE, &rclUpdate);
  348.             WinEndPaint(hps);
  349.         }
  350.         return (MRESULT)0;
  351.     }
  352.     return WinDefWindowProc(hwnd, msg, mp1, mp2);
  353. }
  354.  
  355. /*
  356.     priority_thread
  357.     This thread controls the priority of the drawing thread.
  358.     With these changes, if a saver module runs on low priority (this is
  359.     the default setting), it rises to normal priority twice a second
  360.     for 0.1 seconds. This should solve the problem that, when very
  361.     time-consuming processes were running, the module seemed not to become
  362.     active at all (in fact it became active, but did not get enough CPU
  363.     time to do its saver action).
  364.     There should be no reason to alter the code.
  365. */
  366. void    priority_thread(void *args)
  367. {
  368.     DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
  369.     for(;;){
  370.         DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, 0, tidDraw);
  371.         DosSleep(100);
  372.         DosSetPriority(PRTYS_THREAD, PRTYC_IDLETIME, 0, tidDraw);
  373.         DosSleep(400);
  374.     }
  375. }
  376.  
  377.  
  378. /*
  379.     load_configuration_data
  380.     Load all module configuration data from the INI-file into the
  381.     configuration_data structure, if not done already loaded.
  382. */
  383. void    load_configuration_data()
  384. {
  385.     if(configuration_data_loaded == FALSE){
  386.         // data not loaded yet
  387.         ULONG    size;
  388.         BOOL    fSuccess;
  389.  
  390.         // get name of the saver module (stored as resource string)
  391.         if(WinLoadString(hab, hmodDLL, IDS_MODULENAME,
  392.           SAVER_NAME_MAXLEN, modulename) == 0){
  393.             // resource string not found. indicate error by
  394.             // setting module name to empty string
  395.             strcpy(modulename, "");
  396.             return;
  397.         }
  398.  
  399.         // load data from INI-file. the key name is the name of the
  400.         // saver module
  401.         size = sizeof(configuration_data);
  402.         fSuccess = PrfQueryProfileData(HINI_USER,
  403.           (PSZ)application_name, (PSZ)modulename,
  404.           (PSZ)&configuration_data, &size);
  405.         if(!fSuccess || size != sizeof(configuration_data) || configuration_data.version != MODULEVERSION){
  406.             // if entry is not found or entry has invalid size or
  407.             // entry has wrong version number, create a new entry
  408.             // with default values and write it to the INI-file
  409.             configuration_data.version = MODULEVERSION;
  410.             configuration_data.enabled = TRUE;
  411.             configuration_data.count   = CONFIGURATION_DEFAULT_COUNT;
  412.                         configuration_data.sides   = CONFIGURATION_POLY_DEFAULT_COUNT;
  413.             configuration_data.closed  = CONFIGURATION_POLY_DEFAULT_CLOSED;
  414.             configuration_data.use_line= TRUE;
  415.                         configuration_data.use_curve = FALSE;
  416.  
  417.             PrfWriteProfileData(HINI_USER, (PSZ)application_name, (PSZ)modulename, (PSZ)&configuration_data, sizeof(configuration_data));
  418.         }
  419.         configuration_data_loaded = TRUE;
  420.     }
  421. }
  422.  
  423. /*
  424.     draw_thread
  425.     This is the drawing-thread.
  426.     You have a valid presentation space handle (hps), a valid window
  427.     handle (hwndSaver) and the configuration_data structure is loaded.
  428.     The screen size is store in "screenSizeX" and "screenSizeY".
  429.     IMPORTANT NOTE 1:
  430.     You must check the "stop_draw_thread" flag regularly. If it is set,
  431.     free all resources you have allocated and call DosExit (or just
  432.     return) to end the drawing-thread.
  433.     IMPORTANT NOTE 2:
  434.     If the "low_priority" flag is NOT set (that means you run with
  435.     regular priority, sharing CPU usage with other programs), you should
  436.     call DosSleep(x) with "x" set at least to 1 as often as possible, to
  437.     allow other programs to do their work. A screen saver should not eat
  438.     up other program's CPU time!
  439.     IMPORTANT NOTE 3:
  440.     For some of the PM calls to work properly, your thread needs an
  441.     own HAB and maybe even a message queue. You have to get and release
  442.     both of them here if you use those PM calls.
  443.  
  444.     The following sample code is from the "Pyramids" module that comes
  445.     with the ScreenSaver distribution.
  446.     It selects a random color and a random point on the screen, then
  447.     draws lines in the selected color from each corner of the screen
  448.     to the selected point (looks somewhat like a pyramid).
  449.     It remembers a number of points (this number can be set in the
  450.     configuration dialog). Having filled the point memory, it redraws
  451.     the "oldest" visible pyramid in black. This has the effect that more
  452.     and more pixels on the screen get black, only a few constantly
  453.     changing colored lines remain.
  454. */
  455. void    draw_thread(void *args)
  456. {
  457.     POINTL    *pt;
  458.     POINTL  *last_pt;
  459.     POINTL  *delta;
  460.     int        i, j;
  461.     BOOL    point_buffer_filled = FALSE;
  462.     RECTL   ScreenSize;
  463.     long    Color_Counter,counter, Color;
  464.     int     PolyNumber,k;
  465.     HAB        drawingthread_hab = WinInitialize(0);
  466.     HMQ        drawingthread_hmq = WinCreateMsgQueue(drawingthread_hab, 0);
  467.  
  468.     i = j = counter = 0;
  469.     PolyNumber = configuration_data.sides + 1;
  470.     point_buffer_filled = FALSE;
  471.  
  472.     // allocate stack memory for circular point buffer
  473.     pt      = malloc(configuration_data.count * PolyNumber * sizeof(POINTL));
  474.     last_pt = malloc(PolyNumber * sizeof(POINTL));
  475.     delta   = malloc(PolyNumber * sizeof(POINTL));
  476.  
  477.     for ( k = 0 ; k < PolyNumber ; k++ )
  478.         {
  479.         delta[k].x = (((unsigned)rand()) % 20) - 10;
  480.         delta[k].y = (((unsigned)rand()) % 20) - 10;
  481.         } /* endfor */
  482.  
  483.     // Set initial coordinate.
  484.     for ( k = 0 ; k < PolyNumber ; k++ )
  485.         {
  486.         pt[k].x = ((unsigned)rand()) % screenSizeX;
  487.         pt[k].y = ((unsigned)rand()) % screenSizeY;
  488.         last_pt[k] = pt[k];
  489.         }
  490.   
  491.     Color_Counter = 100 + ((unsigned)rand()) % 1000;
  492.     Color = ((unsigned)rand()) % 16;
  493.     if ((Color == CLR_NEUTRAL ) && ( Color == CLR_BACKGROUND ))
  494.          Color++; 
  495.     GpiSetColor(hps, Color );
  496.     WinQueryWindowRect( hwndSaver, &ScreenSize );
  497.     WinFillRect( hps, &ScreenSize, CLR_BLACK );
  498.  
  499.     while(!stop_draw_thread)
  500.         {
  501.         // select random color
  502.         GpiSetColor(hps, Color );
  503.         if (counter == Color_Counter) 
  504.             {
  505.             for ( k = 0 ; k < PolyNumber ; k++ )
  506.                {
  507.                delta[k].x = (((unsigned)rand()) % 20) - 10;
  508.                delta[k].y = (((unsigned)rand()) % 20) - 10;
  509.                } /* endfor */
  510.             Color_Counter = 100 + ((unsigned)rand()) % 1000; 
  511.             Color = ((unsigned)rand()) % 16;
  512.             if ((Color == CLR_NEUTRAL ) && ( Color == CLR_BACKGROUND ))
  513.                Color++;      
  514.             counter = 0;
  515.             }
  516.         counter++;
  517.        
  518.         for ( k = 0 ; k < PolyNumber ; k++ )
  519.             {
  520.             // Add deltas to the start and end points for a line.
  521.             // If the start point would be invalid then negate the delta.
  522.  
  523.             if ( (last_pt[k].x + delta[k].x ) > screenSizeX )
  524.                 delta[k].x = -delta[k].x;
  525.             else if ( ( last_pt[k].x + delta[k].x ) < 1 )
  526.                 delta[k].x = -delta[k].x;
  527.  
  528.             if ( ( last_pt[k].y + delta[k].y ) > screenSizeY )
  529.                 delta[k].y = -delta[k].y;
  530.             else if ( ( last_pt[k].y + delta[k].y ) < 1 )
  531.                 delta[k].y = -delta[k].y;
  532.  
  533.             // Add delta to start point.
  534.  
  535.             pt[k + i].x = last_pt[k].x + delta[k].x;
  536.             pt[k + i].y = last_pt[k].y + delta[k].y;
  537.             last_pt[k] = pt[k + i];
  538.             }
  539.         
  540.         // Now draw the line.
  541.  
  542.       GpiMove ( hps , &pt[i] );
  543.  
  544.       if ( configuration_data.use_line )
  545.          GpiPolyLine ( hps , PolyNumber - 1 , &pt[i+1]);
  546.       if ( configuration_data.use_curve )
  547.          GpiPolyFillet ( hps , PolyNumber - 1 , &pt[i+1]);
  548.        
  549.       if (configuration_data.closed)
  550.          GpiLine ( hps , &pt[i]);
  551.        
  552.        // move circular buffer index
  553.  
  554.        i += PolyNumber;
  555.        if( i > (configuration_data.count * PolyNumber) )
  556.             {
  557.             i = 0;
  558.             point_buffer_filled = TRUE;
  559.             }
  560.  
  561.        if(point_buffer_filled)
  562.             {
  563.             // redraw old lines in black
  564.             GpiSetColor(hps, CLR_BLACK);
  565.             GpiMove ( hps , &pt[i] );
  566.             if ( configuration_data.use_line )
  567.                               GpiPolyLine ( hps , PolyNumber - 1 , &pt[i+1]);
  568.                         if ( configuration_data.use_curve )
  569.                               GpiPolyFillet ( hps , PolyNumber - 1 , &pt[i+1]);
  570.                         if (configuration_data.closed)
  571.                           GpiLine ( hps , &pt[i]);
  572.             }
  573.  
  574.     // sleep a while if necessary
  575.     if(low_priority == FALSE)
  576.         DosSleep(1);
  577.     }
  578.     // free resources
  579.     free ( pt );
  580.     free ( last_pt );
  581.     free ( delta );
  582.     
  583.     WinDestroyMsgQueue(drawingthread_hmq);
  584.     WinTerminate(drawingthread_hab);
  585.  
  586. }
  587.